home *** CD-ROM | disk | FTP | other *** search
/ Programming a Multiplayer FPS in DirectX / Programming a Multiplayer FPS in DirectX (Companion CD).iso / DirectX / dxsdk_oct2004.exe / dxsdk.exe / Samples / C++ / DirectInput / DIConfig / privcom.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  2004-09-27  |  13.9 KB  |  510 lines

  1. #include "common.hpp"
  2.  
  3.  
  4. /*****************************************************************************
  5.  *
  6.  *  privcom.c
  7.  *
  8.  *  Copyright (c) Microsoft Corporation.  All Rights Reserved.
  9.  *
  10.  *  Abstract:
  11.  *
  12.  *      Functions that sort-of duplicate what OLE does.
  13.  *
  14.  *****************************************************************************/
  15.  
  16.  
  17.     typedef LPUNKNOWN PUNK;
  18.     typedef LPVOID PV, *PPV;
  19.     typedef CONST VOID *PCV;
  20.     typedef REFIID RIID;
  21.     typedef CONST GUID *PCGUID;
  22.  
  23.     /*
  24.      * Convert an object (X) to a count of bytes (cb).
  25.      */
  26. #define cbX(X) sizeof(X)
  27.  
  28.     /*
  29.      * Convert an array name (A) to a generic count (c).
  30.      */
  31. #define cA(a) (cbX(a)/cbX(a[0]))
  32.  
  33.     /*
  34.      * Convert a count of X's (cx) into a count of bytes
  35.      * and vice versa.
  36.      */
  37. #define  cbCxX(cx, X) ((cx) * cbX(X))
  38. #define  cxCbX(cb, X) ((cb) / cbX(X))
  39.  
  40.     /*
  41.      * Convert a count of chars (cch), tchars (ctch), wchars (cwch),
  42.      * or dwords (cdw) into a count of bytes, and vice versa.
  43.      */
  44. #define  cbCch(cch)  cbCxX( cch,  CHAR)
  45. #define cbCwch(cwch) cbCxX(cwch, WCHAR)
  46. #define cbCtch(ctch) cbCxX(ctch, TCHAR)
  47. #define  cbCdw(cdw)  cbCxX( cdw, DWORD)
  48.  
  49. #define  cchCb(cb) cxCbX(cb,  CHAR)
  50. #define cwchCb(cb) cxCbX(cb, WCHAR)
  51. #define ctchCb(cb) cxCbX(cb, TCHAR)
  52. #define  cdwCb(cb) cxCbX(cb, DWORD)
  53.  
  54. // yay
  55. #define ctchGuid    (1 + 8 + 1 + 4 + 1 + 4 + 1 + 4 + 1 + 12 + 1 + 1)
  56.  
  57. /*****************************************************************************
  58.  *
  59.  *  _ParseHex
  60.  *
  61.  *      Parse a hex string encoding cb bytes (at most 4), then
  62.  *      expect the tchDelim to appear afterwards.  If chDelim is 0,
  63.  *      then no delimiter is expected.
  64.  *
  65.  *      Store the result into the indicated LPBYTE (using only the
  66.  *      size requested), updating it, and return a pointer to the
  67.  *      next unparsed character, or 0 on error.
  68.  *
  69.  *      If the incoming pointer is also 0, then return 0 immediately.
  70.  *
  71.  *****************************************************************************/
  72.  
  73. LPCTSTR 
  74.     _ParseHex(LPCTSTR ptsz, LPBYTE *ppb, int cb, TCHAR tchDelim)
  75. {
  76.     if(ptsz)
  77.     {
  78.         int i = cb * 2;
  79.         DWORD dwParse = 0;
  80.  
  81.         do
  82.         {
  83.             DWORD uch;
  84.             uch = (TBYTE)*ptsz - TEXT('0');
  85.             if(uch < 10)
  86.             {             /* a decimal digit */
  87.             } else
  88.             {
  89.                 uch = (*ptsz | 0x20) - TEXT('a');
  90.                 if(uch < 6)
  91.                 {          /* a hex digit */
  92.                     uch += 10;
  93.                 } else
  94.                 {
  95.                     return 0;           /* Parse error */
  96.                 }
  97.             }
  98.             dwParse = (dwParse << 4) + uch;
  99.             ptsz++;
  100.         } while(--i);
  101.  
  102.         if(tchDelim && *ptsz++ != tchDelim) return 0; /* Parse error */
  103.  
  104.         for(i = 0; i < cb; i++)
  105.         {
  106.             (*ppb)[i] = ((LPBYTE)&dwParse)[i];
  107.         }
  108.         *ppb += cb;
  109.     }
  110.     return ptsz;
  111. }
  112.  
  113. /*****************************************************************************
  114.  *
  115.  *  @doc    INTERNAL
  116.  *
  117.  *  @func   BOOL | ParseGUID |
  118.  *
  119.  *          Take a string and convert it into a GUID, return success/failure.
  120.  *
  121.  *  @parm   OUT LPGUID | lpGUID |
  122.  *
  123.  *          Receives the parsed GUID on success.
  124.  *
  125.  *  @parm   IN LPCTSTR | ptsz |
  126.  *
  127.  *          The string to parse.  The format is
  128.  *
  129.  *      { <lt>dword<gt> - <lt>word<gt> - <lt>word<gt>
  130.  *                      - <lt>byte<gt> <lt>byte<gt>
  131.  *                      - <lt>byte<gt> <lt>byte<gt> <lt>byte<gt>
  132.  *                        <lt>byte<gt> <lt>byte<gt> <lt>byte<gt> }
  133.  *
  134.  *  @returns
  135.  *
  136.  *          Returns zero if <p ptszGUID> is not a valid GUID.
  137.  *
  138.  *
  139.  *  @comm
  140.  *
  141.  *          Stolen from TweakUI.
  142.  *
  143.  *****************************************************************************/
  144.  
  145. BOOL 
  146.     ParseGUID(LPGUID pguid, LPCTSTR ptsz)
  147. {
  148.     if(lstrlen(ptsz) == ctchGuid - 1 && *ptsz == TEXT('{'))
  149.     {
  150.         ptsz++;
  151.         ptsz = _ParseHex(ptsz, (LPBYTE *)&pguid, 4, TEXT('-'));
  152.         ptsz = _ParseHex(ptsz, (LPBYTE *)&pguid, 2, TEXT('-'));
  153.         ptsz = _ParseHex(ptsz, (LPBYTE *)&pguid, 2, TEXT('-'));
  154.         ptsz = _ParseHex(ptsz, (LPBYTE *)&pguid, 1,       0  );
  155.         ptsz = _ParseHex(ptsz, (LPBYTE *)&pguid, 1, TEXT('-'));
  156.         ptsz = _ParseHex(ptsz, (LPBYTE *)&pguid, 1,       0  );
  157.         ptsz = _ParseHex(ptsz, (LPBYTE *)&pguid, 1,       0  );
  158.         ptsz = _ParseHex(ptsz, (LPBYTE *)&pguid, 1,       0  );
  159.         ptsz = _ParseHex(ptsz, (LPBYTE *)&pguid, 1,       0  );
  160.         ptsz = _ParseHex(ptsz, (LPBYTE *)&pguid, 1,       0  );
  161.         ptsz = _ParseHex(ptsz, (LPBYTE *)&pguid, 1, TEXT('}'));
  162.         return (BOOL)(UINT_PTR)ptsz;
  163.     } else
  164.     {
  165.         return 0;
  166.     }
  167. }
  168.  
  169. /*****************************************************************************
  170.  *
  171.  *  @doc    INTERNAL
  172.  *
  173.  *  @func   LONG | RegQueryString |
  174.  *
  175.  *          Wrapper for <f RegQueryValueEx> that reads a
  176.  *          string value from the registry.  An annoying quirk
  177.  *          is that on Windows NT, the returned string might
  178.  *          not end in a null terminator, so we might need to add
  179.  *          one manually.
  180.  *
  181.  *  @parm   IN HKEY | hk |
  182.  *
  183.  *          Parent registry key.
  184.  *
  185.  *  @parm   LPCTSTR | ptszValue |
  186.  *
  187.  *          Value name.
  188.  *
  189.  *  @parm   LPTSTR | ptsz |
  190.  *
  191.  *          Output buffer.
  192.  *
  193.  *  @parm   DWORD | ctchBuf |
  194.  *
  195.  *          Size of output buffer.
  196.  *
  197.  *  @returns
  198.  *
  199.  *          Registry error code.
  200.  *
  201.  *****************************************************************************/
  202.  
  203. LONG 
  204.     RegQueryString(HKEY hk, LPCTSTR ptszValue, LPTSTR ptszBuf, DWORD ctchBuf)
  205. {
  206.     LONG lRc;
  207.     DWORD reg;
  208.  
  209.     #ifdef UNICODE
  210.     DWORD cb;
  211.  
  212.     /*
  213.      *  NT quirk: Non-null terminated strings can exist.
  214.      */
  215.     cb = cbCtch(ctchBuf);
  216.     lRc = RegQueryValueEx(hk, ptszValue, 0, ®, (LPBYTE)(PV)ptszBuf, &cb);
  217.     if(lRc == ERROR_SUCCESS)
  218.     {
  219.         if(reg == REG_SZ)
  220.         {
  221.             /*
  222.              *  Check the last character.  If it is not NULL, then
  223.              *  append a NULL if there is room.
  224.              */
  225.             DWORD ctch = ctchCb(cb);
  226.             if(ctch == 0)
  227.             {
  228.                 ptszBuf[ctch] = TEXT('\0');
  229.             } else if(ptszBuf[ctch-1] != TEXT('\0'))
  230.             {
  231.                 if(ctch < ctchBuf)
  232.                 {
  233.                     ptszBuf[ctch] = TEXT('\0');
  234.                 } else
  235.                 {
  236.                     lRc = ERROR_MORE_DATA;
  237.                 }
  238.             }
  239.         } else
  240.         {
  241.             lRc = ERROR_INVALID_DATA;
  242.         }
  243.     }
  244.  
  245.  
  246.     #else
  247.  
  248.     /*
  249.      *  This code is executed only on Win95, so we don't have to worry
  250.      *  about the NT quirk.
  251.      */
  252.  
  253.     lRc = RegQueryValueEx(hk, ptszValue, 0, ®, (LPBYTE)(PV)ptszBuf, &ctchBuf);
  254.  
  255.     if(lRc == ERROR_SUCCESS && reg != REG_SZ)
  256.     {
  257.         lRc = ERROR_INVALID_DATA;
  258.     }
  259.  
  260.  
  261.     #endif
  262.  
  263.     return lRc;
  264. }
  265.  
  266. /*****************************************************************************
  267.  *
  268.  *  @doc    INTERNAL
  269.  *
  270.  *  @func   HRESULT | _CreateInstance |
  271.  *
  272.  *          Worker function for <f DICoCreateInstance>.
  273.  *
  274.  *  @parm   REFCLSID | rclsid |
  275.  *
  276.  *          The <t CLSID> to create.
  277.  *
  278.  *  @parm   LPCTSTR | ptszDll |
  279.  *
  280.  *          The name of the DLL to load.
  281.  *
  282.  *  @parm   LPUNKNOWN | punkOuter |
  283.  *
  284.  *          Controlling unknown for aggregation.
  285.  *
  286.  *  @parm   RIID | riid |
  287.  *
  288.  *          Interface to obtain.
  289.  *
  290.  *  @parm   PPV | ppvOut |
  291.  *
  292.  *          Receives a pointer to the created object if successful.
  293.  *
  294.  *  @parm   HINSTANCE * | phinst |
  295.  *
  296.  *          Receives the instance handle of the in-proc DLL that was
  297.  *          loaded.  <f FreeLibrary> this DLL when you are finished
  298.  *          with the object.
  299.  *
  300.  *          Note that since we don't implement a binder, this means
  301.  *          that you cannot give the returned pointer away to anybody
  302.  *          you don't control; otherwise, you won't know when to
  303.  *          free the DLL.
  304.  *
  305.  *  @returns
  306.  *
  307.  *          Standard OLE status code.
  308.  *
  309.  *****************************************************************************/
  310.  
  311. HRESULT
  312. _CreateInprocObject(BOOL bInstance, REFCLSID rclsid, LPCTSTR ptszDll, LPUNKNOWN punkOuter,
  313.                 REFIID riid, LPVOID *ppvOut, HINSTANCE *phinst)
  314. {
  315.     HRESULT hres;
  316.     HINSTANCE hinst;
  317.  
  318.     hinst = LoadLibrary(ptszDll);
  319.     if (hinst) {
  320.         LPFNGETCLASSOBJECT DllGetClassObject;
  321.  
  322.         DllGetClassObject = (LPFNGETCLASSOBJECT)
  323.                             GetProcAddress(hinst, "DllGetClassObject");
  324.  
  325.         if (DllGetClassObject) {
  326.             IClassFactory *pcf;
  327.  
  328.             if (bInstance)
  329.                 hres = DllGetClassObject(rclsid, IID_IClassFactory, (LPVOID *)&pcf);
  330.             else
  331.             {
  332.                 hres = DllGetClassObject(rclsid, riid, ppvOut);
  333.                 if (FAILED(hres))
  334.                     *ppvOut = NULL;
  335.             }
  336.             if (SUCCEEDED(hres) && bInstance) {
  337.                 hres = pcf->CreateInstance(punkOuter, riid, ppvOut);
  338.                 pcf->Release();
  339.  
  340.                 /*
  341.                  *  People forget to adhere to
  342.                  *  the OLE spec, which requires that *ppvOut be
  343.                  *  set to zero on failure.
  344.                  */
  345.                 if (FAILED(hres)) {
  346. /*                    if (*ppvOut) {
  347.                         RPF("ERROR! CoCreateInstance: %s forgot to zero "
  348.                             "out *ppvOut on failure path", ptszDll);
  349.                     }*/
  350.                     *ppvOut = 0;
  351.                 }
  352.  
  353.             }
  354.         } else {
  355.             /*
  356.              *  DLL does not export GetClassObject.
  357.              */
  358.             hres = REGDB_E_CLASSNOTREG;
  359.         }
  360.  
  361.         if (SUCCEEDED(hres)) {
  362.             *phinst = hinst;
  363.         } else {
  364.             FreeLibrary(hinst);
  365.         }
  366.     } else {
  367.         /*
  368.          *  DLL does not exist.
  369.          */
  370.         hres = REGDB_E_CLASSNOTREG;
  371.     }
  372.  
  373.     return hres;
  374. }
  375.  
  376.  
  377. /*****************************************************************************
  378.  *
  379.  *  @doc    INTERNAL
  380.  *
  381.  *  @func   HRESULT | DICoCreateInstance |
  382.  *
  383.  *          Private version of CoCreateInstance that doesn't use OLE.
  384.  *
  385.  *  @parm   LPTSTR | ptszClsid |
  386.  *
  387.  *          The string version of the <t CLSID> to create.
  388.  *
  389.  *  @parm   LPUNKNOWN | punkOuter |
  390.  *
  391.  *          Controlling unknown for aggregation.
  392.  *
  393.  *  @parm   RIID | riid |
  394.  *
  395.  *          Interface to obtain.
  396.  *
  397.  *  @parm   PPV | ppvOut |
  398.  *
  399.  *          Receives a pointer to the created object if successful.
  400.  *
  401.  *  @parm   HINSTANCE * | phinst |
  402.  *
  403.  *          Receives the instance handle of the in-proc DLL that was
  404.  *          loaded.  <f FreeLibrary> this DLL when you are finished
  405.  *          with the object.
  406.  *
  407.  *          Note that since we don't implement a binder, this means
  408.  *          that you cannot give the returned pointer away to anybody
  409.  *          you don't control; otherwise, you won't know when to
  410.  *          free the DLL.
  411.  *
  412.  *  @returns
  413.  *
  414.  *          Standard OLE status code.
  415.  *
  416.  *****************************************************************************/
  417.  
  418. STDMETHODIMP
  419. CreateInprocObject(BOOL bInstance, LPCTSTR ptszClsid, LPUNKNOWN punkOuter,
  420.                    REFIID riid, LPVOID *ppvOut, HINSTANCE *phinst)
  421. {
  422.     HRESULT hres;
  423.     CLSID clsid;
  424.  
  425.     *ppvOut = 0;
  426.     *phinst = 0;
  427.  
  428.     if (ParseGUID(&clsid, ptszClsid)) {
  429.         HKEY hk;
  430.         LONG lRc;
  431.         TCHAR tszKey[ctchGuid + 40];    /* 40 is more than enough */
  432.  
  433.         /*
  434.          *  Look up the CLSID in HKEY_CLASSES_ROOT.
  435.          */
  436.         wsprintf(tszKey, TEXT("CLSID\\%s\\InProcServer32"), ptszClsid);
  437.  
  438.         lRc = RegOpenKeyEx(HKEY_CLASSES_ROOT, tszKey, 0,
  439.                            KEY_QUERY_VALUE, &hk);
  440.         if (lRc == ERROR_SUCCESS) {
  441.             TCHAR tszDll[MAX_PATH];
  442.             DWORD cb;
  443.  
  444.             cb = cbX(tszDll);
  445.             lRc = RegQueryValue(hk, 0, tszDll, (PLONG)&cb);
  446.  
  447.             if (lRc == ERROR_SUCCESS) {
  448.                 TCHAR tszModel[20];     /* more than enough */
  449.  
  450.                 lRc = RegQueryString(hk, TEXT("ThreadingModel"),
  451.                                      tszModel, cA(tszModel));
  452.                 if (lRc == ERROR_SUCCESS &&
  453.                     ((lstrcmpi(tszModel, TEXT("Both"))==0x0) ||
  454.                      (lstrcmpi(tszModel, TEXT("Free"))==0x0))) {
  455.  
  456.                     hres = _CreateInprocObject(bInstance, clsid, tszDll, punkOuter,
  457.                                            riid, ppvOut, phinst);
  458.  
  459.                 } else {
  460.                     /*
  461.                      *  No threading model or bad threading model.
  462.                      */
  463.                     hres = REGDB_E_CLASSNOTREG;
  464.                 }
  465.             } else {
  466.                 /*
  467.                  *  No InprocServer32.
  468.                  */
  469.                 hres = REGDB_E_CLASSNOTREG;
  470.             }
  471.  
  472.             RegCloseKey(hk);
  473.  
  474.         } else {
  475.             /*
  476.              *  CLSID not registered.
  477.              */
  478.             hres = REGDB_E_CLASSNOTREG;
  479.         }
  480.     } else {
  481.         /*
  482.          *  Invalid CLSID string.
  483.          */
  484.         hres = REGDB_E_CLASSNOTREG;
  485.     }
  486.  
  487.     return hres;
  488. }
  489.  
  490.  
  491. HRESULT
  492. PrivCreateInstance(REFCLSID ptszClsid, LPUNKNOWN punkOuter, DWORD dwClsContext, 
  493.                    REFIID riid, LPVOID *ppvOut, HINSTANCE *phinst)
  494. {
  495.     if (dwClsContext != CLSCTX_INPROC_SERVER || phinst == NULL)
  496.         return E_INVALIDARG;
  497.  
  498.     return CreateInprocObject(TRUE, GUIDSTR(ptszClsid), punkOuter, riid, ppvOut, phinst);
  499. }
  500.  
  501. HRESULT
  502. PrivGetClassObject(REFCLSID ptszClsid, DWORD dwClsContext, LPVOID pReserved,
  503.                    REFIID riid, LPVOID *ppvOut, HINSTANCE *phinst)
  504. {
  505.     if (dwClsContext != CLSCTX_INPROC_SERVER || pReserved != NULL || phinst == NULL)
  506.         return E_INVALIDARG;
  507.  
  508.     return CreateInprocObject(FALSE, GUIDSTR(ptszClsid), NULL, riid, ppvOut, phinst);
  509. }
  510.